﻿using System.Runtime.Serialization;
using System;
using Flatland.GeneticProgramming.CoreTypes;

/**
* 
* Copyright (c) 2012 Anders Høst Kjærgaard | ahkj@itu.dk
* 
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, 
* including without limitation the rights to use, copy, modify, merge, publish, distribute, 
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial 
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 
* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

namespace Flatland.GeneticProgramming.Examples {
    /// <summary>
    /// Example class of how a IExpression could be used to solve math problems. 
    /// The class type parameter of int defines the closure type of the expression - only fields of type int,
    /// methods with return type in and parameters of type int will e used in the genetic code.
    /// </summary>
    [Serializable]
    public class MathExample : GenoType, IExpression<int>
    {

        /// <summary>
        ///  Here we declare a variable X that the can be used by the genetic program.
        ///  In this example this is the only class member that will be used as a Terminal in the 
        ///  genetic program. As such, we know the X exists in the genetic code. In contrast, we wouldn't know this if we had
        ///  more variables. (See MathExample2 for example with many vars)
        /// </summary>
        [Primitive]
        public int X;

        /// <summary>
        ///  Public methods will be used as primitives in the function set of the genetic program
        /// </summary>
        [Primitive]
        public int Add(int x, int y) { return x + y; }

        /// <summary>
        ///  Public methods will be used as primitives in the function set of the genetic program
        /// </summary>
        [Primitive]
        public int Sub(int x, int y) { return x - y; }

        /// <summary>
        ///  Public methods will be used as primitives in the function set of the genetic program
        /// </summary>
        [Primitive]
        public int Mul(int x, int y) { return x * y; }

        /// <summary>
        /// Protected modulus.
        /// Some operations may need to be protected in some way. This must be handled by the method declaring the Primitive attribute.
        /// Modulo by zero throws a runtime exception, so we protect it
        /// </summary>
        [Primitive]
        public int Mod(int x, int y) { return y == 0 ? x : x % y; }

        /// <summary>
        /// Protected division.
        /// Some operations may need to be protected in some way. This must be handled by the method declaring the Primitive attribute.
        /// Division by zero will, typically, return 1
        /// </summary>
        [Primitive]
        public int Div(int x, int y) { return y == 0 ? 1 : x / y; }

        /// <summary>
        /// Without attributes the member won't be included in the genetic program.
        /// We can of course, call any public non Primitive attributed member from Primitive methods
        /// </summary>
        private int hiddenValue;

        /// <summary>
        /// Some random function that won't be a part of the genetic code, like thehiddenValue field.
        /// </summary>
        public int HiddenFunc() {
            return hiddenValue;
        }

        /// <summary>
        /// All genes must implement a Fitness function and return a fitness value of the genetic code.
        /// When using IExpression we will often wan to se some variables of the Expression (in this class X)
        /// and the call the Execute method to get the output of the genetic code.
        /// </summary>
        /// <returns></returns>
        public override double Fitness() {
            X = 42;
            int target = 42*42*42;
            int result = (int) Execute();
            return GP.DEFAULT_FITNESS_GOAL - Math.Abs(target - result);
        }

        /// <summary>
        /// Reports are clonable and must reposnd to Clone.
        /// </summary>
        /// <returns></returns>
        public override object Clone() {
            return new MathExample();
        }

        /// <summary>
        /// From base class Behavior. Only needed when used as a GenoType for an Agent. (See CommandExample)
        /// </summary>
        /// <param name="agent"></param>
        protected override void Act(ref string msg) {
            throw new NotImplementedException();
        }

        public MathExample(SerializationInfo info, StreamingContext context) {}
        public MathExample(){}
    }
}
